package com.lambda.security.web.form;

import com.lambda.cloud.core.principal.LoginUser;
import com.lambda.cloud.core.utils.OperatorUtils;
import com.lambda.security.handler.LogoutHandler;
import com.lambda.security.handler.LogoutSuccessHandler;
import com.lambda.security.handler.impl.CompositeLogoutHandler;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.core.log.LogMessage;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;

/**
 * DefaultLogoutFilter
 *
 * @author jpjoo
 */
public class FormLogoutFilter extends GenericFilterBean {
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    private final LogoutHandler handler;
    private final LogoutSuccessHandler logoutSuccessHandler;
    private final String filterProcessesUrl;

    public FormLogoutFilter(LogoutSuccessHandler logoutSuccessHandler, LogoutHandler... handlers) {
        this.handler = new CompositeLogoutHandler(handlers);
        Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
        this.logoutSuccessHandler = logoutSuccessHandler;
        this.filterProcessesUrl = "/logout";
    }

    public FormLogoutFilter(
            String filterProcessesUrl, LogoutSuccessHandler logoutSuccessHandler, LogoutHandler... handlers) {
        Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
        this.logoutSuccessHandler = logoutSuccessHandler;
        this.filterProcessesUrl = filterProcessesUrl;
        this.handler = new CompositeLogoutHandler(handlers);
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        this.doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
    }

    private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (this.requiresLogout(request)) {
            LoginUser loginUser = OperatorUtils.getOperator();
            if (this.logger.isDebugEnabled()) {
                this.logger.debug(LogMessage.format("Logging out [%s]", loginUser));
            }
            this.handler.logout(request, response, loginUser);
            this.logoutSuccessHandler.onLogoutSuccess(request, response, loginUser);
        } else {
            chain.doFilter(request, response);
        }
    }

    protected boolean requiresLogout(HttpServletRequest request) {
        if (antPathMatcher.match(this.filterProcessesUrl, request.getRequestURI())) {
            return true;
        } else {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace(LogMessage.format("Did not match request to %s", this.filterProcessesUrl));
            }
            return false;
        }
    }
}
